[IA64] kexec: Unpin TLB in the hypervisor
authorAlex Williamson <alex.williamson@hp.com>
Fri, 29 Feb 2008 16:18:01 +0000 (09:18 -0700)
committerAlex Williamson <alex.williamson@hp.com>
Fri, 29 Feb 2008 16:18:01 +0000 (09:18 -0700)
The dom0 relocate_new_kernel code makes a large number of assumptions about
various compile time constants, and thus assumes that these constants are
the same for the hypervisor and dom0. Despite extensive #ifdef work this
has proved to be both fragile and incomplete.

This patch changes things around so that the unpinning work is done
by code provided by the hypervisor, reusing existing code there.
Apart from being a solution that works, its also likely
a much more maintainable solution, as as TLB changes in the hypervisor
code are made, the code paths in the hypervisor are much more likely
to be checked than this one which lies in a completely different tree.

There is also a dom0 Linux kernel portion to this patch.
Its commit message has comments detailing various implementation
issues. See linux-2.6.18-xen.hg ee7015727bd15e80e17e725f70c0a5336e45607a

Signed-off-by: Simon Horman <horms@verge.net.au>
xen/arch/ia64/xen/machine_kexec.c
xen/arch/ia64/xen/relocate_kernel.S
xen/include/asm-ia64/kexec.h

index b9c78fd9ed972326b1d822733588ab05711619ec..849a395f2396b85b4d3eee9e94fdd4614212b99f 100644 (file)
 #include <linux/notifier.h>
 #include <asm/dom_fw_dom0.h>
 
-typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)(
-                                       unsigned long indirection_page,
-                                       unsigned long start_address,
-                                       struct ia64_boot_param *boot_param,
-                                       unsigned long pal_addr,
-                                       unsigned long cpu_data_pa,
-                                       unsigned long kernel_start,
-                                       unsigned long page_offset,
-                                       unsigned long vhpt)
-                                       ATTRIB_NORET;
-
 #define kexec_flush_icache_page(page)                                  \
 do {                                                                   \
        unsigned long page_addr = (unsigned long)page_address(page);    \
@@ -54,12 +43,6 @@ void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image)
 static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
 {
        xen_kexec_image_t *image = arg;
-       relocate_new_kernel_t rnk;
-       unsigned long code_addr = (unsigned long)
-                                 __va(image->reboot_code_buffer);
-       unsigned long cpu_data_pa = (unsigned long)
-                                 __pa(cpu_data(smp_processor_id()));
-       unsigned long vhpt;
        int ii;
 
        /* Interrupts aren't acceptable while we reboot */
@@ -84,12 +67,8 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
        while (ia64_get_ivr() != IA64_SPURIOUS_INT_VECTOR)
                ia64_eoi();
        platform_kernel_launch_event();
-       vhpt = __va_ul(vcpu_vhpt_maddr(current));
-       BUG_ON(!vhpt);
-       rnk = (relocate_new_kernel_t)&code_addr;
-       (*rnk)(image->indirection_page, image->start_address, ia64_boot_param,
-              GRANULEROUNDDOWN((unsigned long) pal_vaddr), cpu_data_pa,
-              KERNEL_START, PAGE_OFFSET, vhpt);
+       relocate_new_kernel(image->indirection_page, image->start_address,
+                           __pa(ia64_boot_param), image->reboot_code_buffer);
        BUG();
 }
 
index 8b440a5f382713b6933d1fd2a40258061750cbd3..b0ab86c3d49a5f7335c6016bfca509c3dc5d3f52 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/mca_asm.h>
 
+/* relocate_new_kernel
+ *
+ * Do all the unpinning here, as the hypervisor has all the relevant
+ * variables and constants. Then go into the reboot_code_buffer to
+ * relocaate the new kernel and then branch into purgatory.
+ *
+ * Based on ia64_jump_to_sal
+ *
+ * in0: indirection_page
+ * in1: start_address
+ * in2: boot_param
+ * in2: dom0_relocate_new_kernel
+ */
+GLOBAL_ENTRY(relocate_new_kernel)
+       .prologue
+       alloc r31=ar.pfs,4,0,4,0
+       .body
+       rsm psr.i  | psr.ic
+{
+       flushrs
+       srlz.i
+}
+       movl r18=tlb_purge_done;;
+       DATA_VA_TO_PA(r18);;
+       mov b1=r18      // Return location
+       movl r18=ia64_do_tlb_purge;;
+       DATA_VA_TO_PA(r18);;
+       mov b2=r18      // doing tlb_flush work
+       mov ar.rsc=0    // Put RSE  in enforced lazy, LE mode
+       movl r17=1f;;
+       DATA_VA_TO_PA(r17);;
+       mov cr.iip=r17
+       movl r16=IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC;;
+       mov cr.ipsr=r16
+       mov cr.ifs=r0;;
+       rfi;;
+1:
+        /* Invalidate all TLB data/inst */
+       br.sptk.many b2;; // jump to tlb purge code
+
+tlb_purge_done:
+       mov out0=in0    // out3 is ignored and thus can be garbage
+       mov out1=in1
+       mov out2=in2
+       mov b1=in3
+       ;;
+       br.sptk.many b1;; // jump to dom0-supplied relocate_new_kernel
+
+       /* We should never get here */
+END(relocate_new_kernel)
+
 GLOBAL_ENTRY(ia64_dump_cpu_regs)
         .prologue
         alloc loc0=ar.pfs,1,2,0,0
index 33e94c26e57cf15fe7587e7370d8a5a849054030..97d892838fccbc7bb7b1da9cf7264c3bbe439e2e 100644 (file)
@@ -5,8 +5,10 @@
 #include <xen/kexec.h>
 
 extern const unsigned int relocate_new_kernel_size;
-extern void relocate_new_kernel(unsigned long, unsigned long,
-                                struct ia64_boot_param *, unsigned long);
+extern void relocate_new_kernel(unsigned long indirection_page,
+                                unsigned long start_address,
+                                unsigned long boot_param,
+                                unsigned long dom0_relocate_new_kernel);
 void crash_save_xen_notes(void);
 void machine_kexec(xen_kexec_image_t *image);
 unsigned long kdump_find_rsvd_region(unsigned long size,